
#include <BRender>
#include <BButton>
#include "member_BWidget.h"
#include "member_BPixmap.h"
#include "member_BTexture.h"

using namespace BWE;

#define member					(*(member_BPixmap*)_ptr)
#define member_allocate()		_ptr = new member_BPixmap(this)
#define member_release()		delete (member_BPixmap*)_ptr

BPixmap::BPixmap()
{
	member_allocate();
}
BPixmap::BPixmap(int width, int height)
{
	member_allocate();
	setSize(BSize(width, height));
}
BPixmap::~BPixmap()
{
	member_release();
}

void BPixmap::setWidth(int width)
{
	setSize(BSize(width, member.size.height()));
}
int BPixmap::width() const
{
	return member.size.width();
}

void BPixmap::setHeight(int height)
{
	setSize(BSize(member.size.width(), height));
}
int BPixmap::height() const
{
	return member.size.height();
}

void BPixmap::setSize(int width, int height)
{
	setSize(BSize(width, height));
}
void BPixmap::setSize(const BSize& size)
{
	if (member.size != size)
	{
		member.size = size;
		member.fbo_resized = true;
		emit(Signal_Resize, size);
		this->dirty();
	}
}
const BSize& BPixmap::size() const
{
	return member.size;
}

void BPixmap::setColor(BByte r, BByte g, BByte b, BByte a)
{
	setColor(BColor(r, g, b, a));
}
void BPixmap::setColor(const BColor& color)
{
	if (member.color != color)
	{
		member.color = color;
		this->dirty();
	}
}
const BColor& BPixmap::color() const
{
	return member.color;
}

bool BPixmap::addWidget(BWidget* widget)
{
	if (!widget)
		return false;
	if (!member.widgets.contain(widget))
	{
		member.widgets.append(widget);
		widget_member(widget)->pixmap = this;
		if (!widget_member(widget)->parent)
		{
			if (widget_member(widget)->dirtyStyle)
			{
				BEvent event(Event_Style);
				widget_member(widget)->dispenseStyles(event);
				widget_member(widget)->dirtyStyle = false;
			}
			if (widget_member(widget)->visible)
			{
				widget_member(widget)->refresh = true;
			}
		}
		this->dirty();
	}
	return true;
}
bool BPixmap::removeWidget(BWidget* widget)
{
	if (member.widgets.contain(widget))
	{
		widget_member(widget)->pixmap = 0;
		member.widgets.remove(widget);
		if (member.focusWidget == widget)
			member.focusWidget = 0;
		if (member.hoverWidget == widget)
			member.hoverWidget = 0;
		member.popupWidgets.remove(widget);
		this->dirty();
		return true;
	}
	return false;
}
void BPixmap::clearWidgets()
{
	if (member.widgets.size())
	{
		member.widgets.clear();
		this->dirty();
	}
}

int BPixmap::widgetCount() const
{
	return member.widgets.size();
}
BWidget* BPixmap::widget(int index)
{
	return member.widgets(index);
}
const BWidget* BPixmap::widget(int index) const
{
	return member.widgets(index);
}

BWidget* BPixmap::widgetAt(const BPoint& pos)
{
	return member.widgetUnderPoint(pos);
}
const BWidget* BPixmap::widgetAt(const BPoint& pos) const
{
	return member.widgetUnderPoint(pos);
}

bool BPixmap::capture(BImage* image)
{
	if (image == 0 || member.size.empty())
		return false;
	image->setSize(member.size);
	Format format = image->format();
	BByteArray* pixels = image->pixels();
	if (format == Format_RGBA && pixels)
	{
		glReadPixels(0, 0, member.size.width(), member.size.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels->data());
	}
	if (format == Format_RGB && pixels)
	{
		glReadPixels(0, 0, member.size.width(), member.size.height(), GL_RGB, GL_UNSIGNED_BYTE, pixels->data());
	}
	if (format == Format_Gray_Alpha && pixels)
	{
		glReadPixels(0, 0, member.size.width(), member.size.height(), GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels->data());
	}
	if (format == Format_Gray && pixels)
	{
		glReadPixels(0, 0, member.size.width(), member.size.height(), GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels->data());
	}
	image->dirty();
	return true;
}
bool BPixmap::capture(BImage* image, const BRect& rect)
{
	if (image == 0 || rect.empty() || member.size.empty())
		return false;
	image->setSize(rect.size());
	Format format = image->format();
	BByteArray* pixels = image->pixels();
	if (format == Format_RGBA && pixels)
	{
		glReadPixels(0, 0, member.size.width(), member.size.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels->data());
	}
	if (format == Format_RGB && pixels)
	{
		glReadPixels(0, 0, member.size.width(), member.size.height(), GL_RGB, GL_UNSIGNED_BYTE, pixels->data());
	}
	image->dirty();
	return true;
}

void BPixmap::dirty()
{
	texture_member(this)->dirty = true;
	member.dirty = true;
	member.refresh = true;
	emit(Signal_Dirty);
}

bool BPixmap::flush() const
{
	member.fresh();
	BTexture::flush();

	GLuint tbo = texture_member(this)->tbo;
	if (tbo == 0)
		return false;

	if (member.refresh)
	{
		member.frame();
		member.check();
		member.refresh = false;
	}

	return true;
}

bool BPixmap::event(const BEvent& event)
{
	if (member.widgets.empty())
		return false;
	if (event.type() == Event_Update)
	{
		member.update(event);
		return false;
	}
	if (event.type() == Event_Fresh)
	{
		member.fresh();
		if (member.refresh)
			emit(Signal_Fresh);
		return false;
	}
	if (event.type() >= Event_MouseEnter && event.type() <= Event_DoubleClick)
	{
		BMouseEvent mouseEvent = (BMouseEvent&)event;
		member.mouse_pos = mouseEvent.globalPos();
		if (event.type() == Event_MouseMove)
		{
			member.procMouseMove(mouseEvent);
		}
		if (event.type() == Event_MousePress)
		{
			member.procMousePress(mouseEvent);
		}
		if (event.type() == Event_MouseRelease)
		{
			member.procMouseRelease(mouseEvent);
		}
		return false;
	}
	if (event.type() >= Event_Char && event.type() <= Event_KeyDown)
	{
		if (member.focusWidget)
		{
			widget_member(member.focusWidget)->procEvent(event);
			return true;
		}
	}
	return false;
}
